package utils

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"image"
	"image/jpeg"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"strconv"

	"github.com/tendermint/tendermint/types"
	"golang.org/x/image/draw"
)

func ConvertToFile(multipartFile multipart.File) (*os.File, error) {
	// 创建目标文件
	destFile, err := os.Create("fileName.jpg")
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	// 将 multipart.File 内容写入目标文件
	_, err = io.Copy(destFile, multipartFile)
	if err != nil {
		return nil, err
	}

	// 关闭目标文件写入流
	err = destFile.Close()
	if err != nil {
		return nil, err
	}

	// 重新打开目标文件以读取
	destFile, err = os.Open("fileName.jpg")
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	return destFile, nil
}

func Colorhistfeature(file *os.File) ([]float32, error) {

	//解码图像
	img, err := jpeg.Decode(file)
	if err != nil {
		fmt.Println(err)
		fmt.Println("Error: ", err)
		return nil, err
	}
	// 解码图像
	//img, _, err := image.Decode(bytes.NewReader(data))
	// if err != nil {
	// 	fmt.Println(err)
	// 	return nil, fmt.Errorf("failed to decode image: %v", err)
	// }
	// 将图像缩放到固定大小
	width, height := 32, 32
	resizedImg := image.NewGray(image.Rect(0, 0, width, height))
	draw.ApproxBiLinear.Scale(resizedImg, resizedImg.Bounds(), img, img.Bounds(), draw.Over, nil)

	// 提取特征向量
	vector := extractColorhistFeature(resizedImg)
	// fmt.Println("Feature Vector:", vector)
	// fmt.Println(len(vector))
	return vector, nil
}

// extractFeatureVector 提取图像的特征向量
func extractColorhistFeature(img *image.Gray) []float32 {
	bounds := img.Bounds()
	vector := make([]float32, bounds.Dx()*bounds.Dy())

	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
		for x := bounds.Min.X; x < bounds.Max.X; x++ {
			vector[y*bounds.Dx()+x] = float32(img.GrayAt(x, y).Y) / 255.0
		}
	}

	return vector
}

// readBlockDataFromFile 按区块高度读取对应的区块数据

func ReadBlockDataFromFile(height int64) ([][]byte, error) {
	// 文件名为区块高度
	fileName := fmt.Sprintf("block_%d.dat", height)

	// 读取文件内容
	data, err := os.ReadFile(fileName)
	if err != nil {
		return nil, fmt.Errorf("failed to read block data from file: %v", err)
	}

	// 假设每行都是一个 []byte 数据，将文件内容按行分割并返回
	var blockData [][]byte
	lines := splitBytesByNewline(data)
	for _, line := range lines {
		blockData = append(blockData, line)
	}

	return blockData, nil
}

// splitBytesByNewline 按照换行符拆分 []byte
func splitBytesByNewline(data []byte) [][]byte {
	var lines [][]byte
	var start int
	for i := 0; i < len(data); i++ {
		if data[i] == '\n' {
			lines = append(lines, data[start:i])
			start = i + 1
		}
	}
	// 添加最后一行
	if start < len(data) {
		lines = append(lines, data[start:])
	}
	return lines
}

func GetBlockBag(addr string, height int64, chain_id string) (*types.BlockPack, error) {
	url := fmt.Sprintf("http://%s/block_pack?height=%d", addr, height)
	//fmt.Println(url)

	// 发送 GET 请求
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// TODO:KT3 解析 JSON 响应
	// err = json.Unmarshal(body, &blockPack)
	// if err != nil {
	// 	fmt.Println(err)
	// 	continue
	// }
	tx := Read(height, chain_id)
	block := &types.Block{Data: types.Data{Txs: tx}}
	return &types.BlockPack{ProposalBlock: block, Height: height, Chain_id: chain_id, Blockstring: string(body)}, nil
}

func Read(height int64, chain_id string) types.Txs {
	filepath := "/home/llm/tdmt12/full/tendermint_subject2/my_app/blockdata"
	fileName := fmt.Sprintf("%s/block_%d_%s.dat", filepath, height, chain_id)

	file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0777)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	// reader := bufio.NewReader(file)

	var txs types.Txs
	// 读取文件内容
	jsonData, err := os.ReadFile(fileName)
	if err != nil {
		return nil
	}

	// 将 JSON 数据转换为结构体
	err = json.Unmarshal(jsonData, &txs)
	if err != nil {
		return nil
	}
	// for {
	// 	line, _, err := reader.ReadLine()
	// 	if err != nil {
	// 		if errors.Is(err, io.EOF) {
	// 			break
	// 		} else {
	// 			panic(err)
	// 		}
	// 	}
	// 	txs = append(txs, line)
	// }
	return txs
}

// 自定义排序规则
type ByChainID []string

func (a ByChainID) Len() int {
	return len(a)
}

func (a ByChainID) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a ByChainID) Less(i, j int) bool {
	// 获取每个字符串的类型（b或i）和数字部分
	typeI, numI := getTypeAndNumber(a[i])
	typeJ, numJ := getTypeAndNumber(a[j])

	// 首先根据字母 'b' 或 'i' 排序，'b' 优先
	if typeI != typeJ {
		return typeI < typeJ
	}

	// 如果字母相同，按照数字进行排序
	return numI < numJ
}

// 获取字符串的类型（'b' 或 'i'）和数字部分
func getTypeAndNumber(s string) (string, int) {
	// 第一个字符是 'b' 或 'i'
	typ := string(s[0])
	// 提取数字部分
	numStr := s[1:]
	num, _ := strconv.Atoi(numStr)
	return typ, num
}

// 将 []float32 转换为二进制格式（[]byte）
func Float32ToBinary(eigenvalue []float32) ([]byte, error) {
	buf := new(bytes.Buffer)
	for _, v := range eigenvalue {
		// 写入每个 float32 值到 buffer
		if err := binary.Write(buf, binary.LittleEndian, v); err != nil {
			return nil, fmt.Errorf("failed to write float32 to buffer: %v", err)
		}
	}
	return buf.Bytes(), nil
}

// 将二进制数据转换回 []float32
func BinaryToFloat32(data []byte) ([]float32, error) {
	buf := bytes.NewReader(data)
	var eigenvalue []float32
	for {
		var v float32
		err := binary.Read(buf, binary.LittleEndian, &v)
		if err != nil {
			if err.Error() == "EOF" {
				break // 到达数据末尾，退出循环
			}
			return nil, fmt.Errorf("failed to read float32 from binary data: %v", err)
		}
		eigenvalue = append(eigenvalue, v)
	}
	return eigenvalue, nil
}
